package com.example.spider.schedule;

import com.example.spider.starter.SpiderStarter;
import com.example.spider.task.AbstractSpiderTask;
import com.example.spider.task.SpiderManager;
import com.example.spider.task.SpiderTaskQueue;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 爬虫启动器 + 爬虫 manager
 * 单机模式使用，模拟 mq client从Queue里 poolling
 *
 * @author lym
 */
@Slf4j
@Order()
@Component
public class SpiderScheduled implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private SpiderManager spiderManager;

    @Autowired(required = false)
    private List<SpiderStarter> spiderStarters;

    private static volatile boolean triggeredOnStart = false;

    /**
     * 周期从任务队列中拿出所有任务放到队列
     */
    @Scheduled(cron = "*/1 * * * * ?")
    public void starSpider() {
        AbstractSpiderTask<?> task = SpiderTaskQueue.getTask();
        log.trace("getTask success");
        while (task != null && spiderManager.canAccept()) {
            spiderManager.doSpider(task);
            task = SpiderTaskQueue.getTask();
        }
    }

    /**
     * 第一次启动项目时，启动所有爬虫
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        startAllSpiders(contextRefreshedEvent.getApplicationContext());
    }

    /**
     * 启动所有爬虫任务（可选，cluster关闭）
     * 注册定时触发（去任务中心注册，由任务中心定时发消息）
     */
    public void startAllSpiders(ApplicationContext applicationContext) {
        if (triggeredOnStart || CollectionUtils.isEmpty(spiderStarters)) {
            return;
        }
        triggeredOnStart = true;
        for (SpiderStarter spiderStarter : spiderStarters) {
            try {
                // 启动后立即触发
                if (spiderStarter.startOnInit()) {
                    spiderStarter.startSpiders();
                }
                // 定时调度
                if (spiderStarter.enableCronExecute() && spiderStarter.executeCron() != null) {
                    // 集群的话这里加个 redis 3分钟的锁
                    applicationContext.getBean(ThreadPoolTaskScheduler.class).schedule(spiderStarter::startSpiders, new CronTrigger(spiderStarter.executeCron()));
                }
            } catch (Exception e) {
                log.warn("spiderStarter FAIL（SKIP START）!", e);
            }
        }

    }

}
